use std::collections::hash_map::HashMap;

pub struct MemData {
    data: HashMap<Vec<u8>, Vec<u8>>
}

impl MemData {
    pub fn new() -> Self{
        MemData{ 
            data: HashMap::new()
        }
    }
    
    // if key exist -> no-action , return false
    // if key absent -> insert it, return true
    pub fn insert_with_str(&mut self, key: &str, value: &str) -> bool {
        let vec_key = Vec::<u8>::from(key);
        if !self.data.contains_key(&vec_key){
            self.data.insert(vec_key, Vec::<u8>::from(value));
            true
        }
        else{
            false
        }
    }
    pub fn insert_with_bytes(&mut self, key: &[u8], value: &[u8]) -> bool {
        if !self.data.contains_key(key) {
            self.data.insert(Vec::<u8>::from(key), Vec::<u8>::from(value));
            true
        }
        else {
            false
        }
    }
    pub fn insert_with_vec_ref(&mut self, key: &Vec<u8>, value: &Vec<u8>) -> bool {
        if !self.data.contains_key(key) {
            self.data.insert(Clone::clone(key), Clone::clone(value));
            true
        }
        else{
            false
        }
    }
    pub fn insert_with_vec(&mut self, key: Vec<u8>, value: Vec<u8>) -> bool {
        if !self.data.contains_key(&key){
            self.data.insert(key, value);
            true
        }
        else{
            false
        }
    }

    /*
    pub fn insert<K, V>(&mut self, key: &K, value: &V) -> Option<V> 
    {
        self.data.insert(key, value)
    }
    */

    // if key exist -> remove it , return Value
    // if key absent -> no-action, return None
    pub fn remove_with_str(&mut self, key: &str) -> Option<Vec<u8>> {
        self.data.remove(&Vec::<u8>::from(key))
    }
    pub fn remove_with_bytes(&mut self, key: &[u8]) -> Option<Vec<u8>> {
        self.data.remove(key)
    }
    pub fn remove_with_vec_ref(&mut self, key: &Vec<u8>) -> Option<Vec<u8>> {
        self.data.remove(key)
    }
    pub fn remove_with_vec(&mut self, key: Vec<u8>) -> Option<Vec<u8>> {
        self.data.remove(&key)
    }

    // if key exist ->  update it, return Value
    // if key absent -> no-action , ret None
    pub fn update_with_str(&mut self, key: &str, value: &str) -> Option<Vec<u8>> {
        let vec_key = Vec::<u8>::from(key);
        if self.data.contains_key(&vec_key) {
            self.data.insert(vec_key, Vec::<u8>::from(value)) 
        }
        else {
            None
        }
    }
    pub fn update_with_bytes(&mut self, key: &[u8], value: &[u8]) -> Option<Vec<u8>> {
        let vec_key = Vec::<u8>::from(key);
        if self.data.contains_key(&vec_key) {
            self.data.insert(vec_key, Vec::<u8>::from(value)) 
        } 
        else {
            None
        }
    }
    pub fn update_with_vec_ref(&mut self, key: &Vec<u8>, value: &Vec<u8>) -> Option<Vec<u8>> {
        if self.data.contains_key(key) {  
            self.data.insert(Clone::clone(key), Clone::clone(value)) 
        }
        else {
            None
        }
    }
    pub fn update_with_vec(&mut self, key: Vec<u8>, value: Vec<u8>) -> Option<Vec<u8>> {
        if self.data.contains_key(&key) {
            self.data.insert(key, value) 
        }
        else {
            None
        }
    }

    // if key exist -> replace value , return Value
    // if keyabsent -> insert value , return None
    pub fn replace_with_str(&mut self, key: &str, value: &str) -> Option<Vec<u8>> {
        self.data.insert(Vec::<u8>::from(key), Vec::<u8>::from(value))
    }
    pub fn replace_with_bytes(&mut self, key: &[u8], value: &[u8]) -> Option<Vec<u8>> {
        self.data.insert(Vec::<u8>::from(key), Vec::<u8>::from(value))
    }
    pub fn replace_with_vec_ref(&mut self, key: &Vec<u8>, value: &Vec<u8>) -> Option<Vec<u8>> {
        self.data.insert(Clone::clone(key), Clone::clone(value))
    }
    pub fn replace_with_vec(&mut self, key: Vec<u8>, value: Vec<u8>) -> Option<Vec<u8>> {
        self.data.insert(key, value)
    }


    //contains
    pub fn contains_with_str(&self, key: &str) -> bool{
        self.data.contains_key(&Vec::<u8>::from(key))
    }
    pub fn contains_with_bytes(&self, key: &[u8])-> bool{
        self.data.contains_key(key)
    }
    pub fn contains_with_vec_ref(&self, key: &Vec<u8>)->bool{
        self.data.contains_key(key)
    }
    pub fn contains_with_vec(&self, key: Vec<u8>) -> bool {
        self.data.contains_key(&key)
    }

    //if key exist -> return Value ref
    //if key absent -> return None
    pub fn get_with_str(&self, key: &str) -> Option<&Vec<u8>> {
        self.data.get(&Vec::<u8>::from(key))
    }
    pub fn get_with_bytes(&self, key: &[u8]) -> Option<&Vec<u8>> {
        self.data.get(key)
    }
    pub fn get_with_vec_ref(&self, key: &Vec<u8>) -> Option<&Vec<u8>> {
        self.data.get(key)
    }
    pub fn get_with_vec(&self, key: Vec<u8>) -> Option<&Vec<u8>> {
        self.data.get(&key)
    }

    pub fn len(&self) -> usize {
        self.data.len()
    }
}



#[cfg(test)]
mod test {
    use super::*;

    #[test]
    fn test_insert_vec(){
        let mut data = MemData::new();
        {
            let (key, value) = (Vec::<u8>::from("hello"), Vec::<u8>::from("world"));
            assert!(data.insert_with_vec(key, value));
            assert_eq!(1usize, data.len());
        }
        {
            let (key, value) = (Vec::<u8>::from("hello1"), Vec::<u8>::from("world1"));
            assert!(data.insert_with_vec_ref(&key, &value));
        }


        assert!(data.contains_with_str("hello"));
        assert!(data.contains_with_bytes("hello".as_bytes()));
        assert!(data.contains_with_vec_ref(&Vec::<u8>::from("hello")));
    }

    #[test]
    fn test_syntax_array_vec(){
        //equal  Vec<u8>  &[u8]
        let v = vec![1,2,3];
        let a = [1, 2, 3];
        assert_eq!(v, a);

        let mut h: HashMap<Vec<u8>, Vec<u8>> = HashMap::new();
        h.insert(Vec::from("hello"), Vec::from("value"));
        h.contains_key("hello".as_bytes());
    }


}
